#include "wx/wxprec.h"
#include "wx/defs.h"
#include "wx/object.h"
#include "wx/hash.h"
#include "wx/string.h"
#include "wx/log.h"
#include "wx/event.h"
#include "wx/window.h"
#include "wx/panel.h"
#include "wx/dc.h"
#include "wx/dcclient.h"
#include "wx/button.h"
#include "wx/pen.h"
#include "wx/brush.h"
#include "wx/cursor.h"
#include "wx/dialog.h"
#include "wx/settings.h"
#include "wx/msgdlg.h"
#include "wx/choice.h"
#include "wx/stattext.h"
#include "wx/textctrl.h"
#include "wx/scrolwin.h"
#include "wx/dirdlg.h"
#include "wx/combobox.h"
#include "wx/layout.h"
#include "wx/sizer.h"
#include "wx/textdlg.h"
#include "wx/filedlg.h"
#include "wx/intl.h"

#define __wxPG_SOURCE_FILE__

#include <wx/propgrid/propgrid.h>
#include <wx/propgrid/propdev.h>
#include <wx/propgrid/advprops.h>
#include <wx/odcombo.h>

#define wxPG_CAN_DRAW_CURSOR  0

IMPLEMENT_DYNAMIC_CLASS( wxColourPropertyValue, wxObject )

bool operator == ( const wxColourPropertyValue& a, const wxColourPropertyValue& b ) {
  return ( ( a.m_colour == b.m_colour ) && ( a.m_type == b.m_type ) );
}

bool operator == ( const wxArrayInt& array1, const wxArrayInt& array2 ) {
  if( array1.GetCount() != array2.GetCount() ) {
    return false;
  }
  size_t i;
  for( i = 0; i < array1.GetCount(); i++ ) {
    if( array1[i] != array2[i] ) {
      return false;
    }
  }
  return true;
}

#define IS_MOTION_SPIN_SUPPORTED  0

WX_PG_IMPLEMENT_EDITOR_CLASS( SpinCtrl, wxPGSpinCtrlEditor, wxPGEditor )

wxPGSpinCtrlEditor::~wxPGSpinCtrlEditor() {
  wxPG_EDITOR( SpinCtrl ) = NULL;
}

wxPGWindowList wxPGSpinCtrlEditor::CreateControls( wxPropertyGrid* propgrid, wxPGProperty* property,
    const wxPoint& pos, const wxSize& sz ) const {
  const int margin = 1;
  wxSize butSz( 18, sz.y );
  wxSize tcSz( sz.x - butSz.x - margin, sz.y );
  wxPoint butPos( pos.x + tcSz.x + margin, pos.y );
  wxSpinButton* wnd2;
  wnd2 = new wxSpinButton();
  wnd2->Create( propgrid->GetPanel(), wxPG_SUBID2, butPos, butSz, wxSP_VERTICAL );
  wnd2->SetRange( INT_MIN, INT_MAX );
  wnd2->SetValue( 0 );
  propgrid->Connect( wxPG_SUBID1, wxEVT_KEY_DOWN, ( wxObjectEventFunction )( wxEventFunction )( wxCommandEventFunction )
                     &wxPropertyGrid::OnCustomEditorEvent, NULL, propgrid );
  wxTextValidator validator( wxFILTER_NUMERIC, &m_tempString );
  wxTextCtrl* wnd1 = ( wxTextCtrl* ) wxPGTextCtrlEditor::CreateControls( propgrid, property, pos, tcSz ).m_primary;
  wnd1->SetValidator( validator );
  return wxPGWindowList( wnd1, wnd2 );
}

bool wxPGSpinCtrlEditor::OnEvent( wxPropertyGrid* propgrid, wxPGProperty* property, wxWindow* wnd, wxEvent& event ) const {
  int evtType = event.GetEventType();
  int keycode = -1;
  int spins = 1;
  bool bigStep = false;
  if( evtType == wxEVT_KEY_DOWN ) {
    wxKeyEvent& keyEvent = ( wxKeyEvent& )event;
    keycode = keyEvent.GetKeyCode();
    if( keycode == WXK_UP ) {
      evtType = wxEVT_SCROLL_LINEUP;
    } else if( keycode == WXK_DOWN ) {
      evtType = wxEVT_SCROLL_LINEDOWN;
    } else if( keycode == WXK_PAGEUP ) {
      evtType = wxEVT_SCROLL_LINEUP;
      bigStep = true;
    } else if( keycode == WXK_PAGEDOWN ) {
      evtType = wxEVT_SCROLL_LINEDOWN;
      bigStep = true;
    }
  }
  if( evtType == wxEVT_SCROLL_LINEUP || evtType == wxEVT_SCROLL_LINEDOWN ) {
    wxString s;
    wxTextCtrl* tc = wxDynamicCast( propgrid->GetEditorControl(), wxTextCtrl );
    if( tc ) {
      s = tc->GetValue();
    } else {
      s = property->GetValueAsString( wxPG_FULL_VALUE );
    }
    int mode = wxPG_PROPERTY_VALIDATION_SATURATE;
    if( property->GetAttributeAsLong( _T( "Wrap" ), 0 ) ) {
      mode = wxPG_PROPERTY_VALIDATION_WRAP;
    }
    if( property->GetValueType() == _T( "double" ) ) {
      double v_d;
      double step = property->GetAttributeAsDouble( _T( "Step" ), 1.0 );
      if( s.ToDouble( &v_d ) ) {
        if( bigStep ) {
          step *= 10.0;
        }
        step *= ( double ) spins;
        if( evtType == wxEVT_SCROLL_LINEUP ) {
          v_d += step;
        } else {
          v_d -= step;
        }
        wxFloatProperty::DoValidation( property, v_d, NULL, mode );
        wxPropertyGrid::DoubleToString( s, v_d, 6, true, NULL );
      } else {
        return false;
      }
    } else {
      wxLongLong_t v_ll;
      wxLongLong_t step = property->GetAttributeAsLong( _T( "Step" ), 1 );
      if( wxPGStringToLongLong( s, &v_ll, 10 ) ) {
        if( bigStep ) {
          step *= 10;
        }
        step *= spins;
        if( evtType == wxEVT_SCROLL_LINEUP ) {
          v_ll += step;
        } else {
          v_ll -= step;
        }
        wxIntProperty::DoValidation( property, v_ll, NULL, mode );
        s = wxLongLong( v_ll ).ToString();
      } else {
        return false;
      }
    }
    if( tc ) {
      int ip = tc->GetInsertionPoint();
      int lp = tc->GetLastPosition();
      tc->SetValue( s );
      tc->SetInsertionPoint( ip + ( tc->GetLastPosition() - lp ) );
    }
    return true;
  }
  return wxPGTextCtrlEditor::OnEvent( propgrid, property, wnd, event );
}

#include <wx/datectrl.h>
#include <wx/dateevt.h>

class wxPGDatePickerCtrlEditor : public wxPGEditor {
    WX_PG_DECLARE_EDITOR_CLASS( wxPGDatePickerCtrlEditor )
  public:
    virtual ~wxPGDatePickerCtrlEditor();
    wxPG_DECLARE_CREATECONTROLS
    virtual void UpdateControl( wxPGProperty* property, wxWindow* wnd ) const;
    virtual bool OnEvent( wxPropertyGrid* propgrid, wxPGProperty* property, wxWindow* wnd, wxEvent& event ) const;
    virtual bool GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* wnd ) const;
    virtual void SetValueToUnspecified( wxPGProperty * ( property ), wxWindow* wnd ) const;
};


WX_PG_IMPLEMENT_EDITOR_CLASS( DatePickerCtrl, wxPGDatePickerCtrlEditor, wxPGEditor )


wxPGDatePickerCtrlEditor::~wxPGDatePickerCtrlEditor() {
  wxPG_EDITOR( DatePickerCtrl ) = NULL;
}

wxPGWindowList wxPGDatePickerCtrlEditor::CreateControls( wxPropertyGrid* propgrid, wxPGProperty* property,
    const wxPoint& pos, const wxSize& sz ) const {
  wxCHECK_MSG( property->IsKindOf( WX_PG_CLASSINFO( wxDateProperty ) ), NULL, _T( "DatePickerCtrl editor can only be used with wxDateProperty or derivative." ) );
  wxDateProperty* prop = wxDynamicCast( property, wxDateProperty );
  wxDatePickerCtrl* ctrl = new wxDatePickerCtrl();
  wxSize useSz = sz;
  wxDateTime dateValue( wxInvalidDateTime );
  if( prop->GetType() == _T( "datetime" ) ) {
    dateValue = prop->GetDateValue();
  }
  ctrl->Create( propgrid->GetPanel(), wxPG_SUBID1, dateValue, pos, useSz, prop->GetDatePickerStyle() | wxNO_BORDER );
  propgrid->Connect( wxPG_SUBID1, wxEVT_DATE_CHANGED, ( wxObjectEventFunction )( wxEventFunction )( wxCommandEventFunction )
                     &wxPropertyGrid::OnCustomEditorEvent );
  return ctrl;
}

void wxPGDatePickerCtrlEditor::UpdateControl( wxPGProperty* property, wxWindow* wnd ) const {
  wxDatePickerCtrl* ctrl = ( wxDatePickerCtrl* ) wnd;
  wxASSERT( ctrl && ctrl->IsKindOf( CLASSINFO( wxDatePickerCtrl ) ) );
  wxDateTime dateValue( wxInvalidDateTime );
  if( property->GetType() == _T( "datetime" ) ) {
    dateValue = property->GetValue().GetDateTime();
  }
  ctrl->SetValue( dateValue );
}


bool wxPGDatePickerCtrlEditor::OnEvent( wxPropertyGrid * ( propgrid ), wxPGProperty * ( property ),
                                        wxWindow * ( wnd ), wxEvent& event ) const {
  if( event.GetEventType() == wxEVT_DATE_CHANGED ) {
    return true;
  }
  return false;
}

bool wxPGDatePickerCtrlEditor::GetValueFromControl( wxVariant& variant, wxPGProperty * ( property ), wxWindow* wnd ) const {
  wxDatePickerCtrl* ctrl = ( wxDatePickerCtrl* ) wnd;
  wxASSERT( ctrl && ctrl->IsKindOf( CLASSINFO( wxDatePickerCtrl ) ) );
  variant = ctrl->GetValue();
  return true;
}

void wxPGDatePickerCtrlEditor::SetValueToUnspecified( wxPGProperty* property, wxWindow* wnd ) const {
  wxDatePickerCtrl* ctrl = ( wxDatePickerCtrl* ) wnd;
  wxASSERT( ctrl && ctrl->IsKindOf( CLASSINFO( wxDatePickerCtrl ) ) );
  wxDateProperty* prop = wxDynamicCast( property, wxDateProperty );
  if( prop ) {
    int datePickerStyle = prop->GetDatePickerStyle();
    if( datePickerStyle & wxDP_ALLOWNONE ) {
      ctrl->SetValue( wxInvalidDateTime );
    }
  }
}

#include <wx/fontdlg.h>
#include <wx/fontenum.h>

static const wxChar* gs_fp_es_family_labels[] = {
  _T( "Default" ), _T( "Decorative" ),
  _T( "Roman" ), _T( "Script" ),
  _T( "Swiss" ), _T( "Modern" ),
  _T( "Teletype" ), _T( "Unknown" ),
  ( const wxChar* ) NULL
};

static long gs_fp_es_family_values[] = {
  wxFONTFAMILY_DEFAULT, wxFONTFAMILY_DECORATIVE,
  wxFONTFAMILY_ROMAN, wxFONTFAMILY_SCRIPT,
  wxFONTFAMILY_SWISS, wxFONTFAMILY_MODERN,
  wxFONTFAMILY_TELETYPE, wxFONTFAMILY_UNKNOWN
};

static const wxChar* gs_fp_es_style_labels[] = {
  _T( "Normal" ),
  _T( "Slant" ),
  _T( "Italic" ),
  ( const wxChar* ) NULL
};

static long gs_fp_es_style_values[] = {
  wxNORMAL,
  wxSLANT,
  wxITALIC
};

static const wxChar* gs_fp_es_weight_labels[] = {
  _T( "Normal" ),
  _T( "Light" ),
  _T( "Bold" ),
  ( const wxChar* ) NULL
};

static long gs_fp_es_weight_values[] = {
  wxNORMAL,
  wxLIGHT,
  wxBOLD
};

WX_PG_IMPLEMENT_PROPERTY_CLASS( wxFontProperty, wxPGProperty, wxFont, const wxFont&, TextCtrlAndButton )

wxFontProperty::wxFontProperty( const wxString& label, const wxString& name, const wxFont& value )
  : wxPGProperty( label, name ) {
  SetValue( wxFontToVariant( value ) );
  if( !wxPGGlobalVars->m_fontFamilyChoices ) {
    wxFontEnumerator enumerator;
    enumerator.EnumerateFacenames();
    wxArrayString faceNames = enumerator.GetFacenames();
    faceNames.Sort();
    wxPGGlobalVars->m_fontFamilyChoices = new wxPGChoices( faceNames );
  }
  wxString emptyString( wxEmptyString );
  wxFont& font = wxFontFromVariant( m_value );
  AddPrivateChild( new wxIntProperty( _T( "Point Size" ), _T( "Point Size" ), ( long )font.GetPointSize() ) );
  AddPrivateChild( new wxEnumProperty( _T( "Family" ), _T( "Family" ), gs_fp_es_family_labels, gs_fp_es_family_values, font.GetFamily() ) );
  wxString faceName = font.GetFaceName();
  if( faceName.length() &&
      wxPGGlobalVars->m_fontFamilyChoices->Index( faceName ) == wxNOT_FOUND ) {
    wxPGGlobalVars->m_fontFamilyChoices->AddAsSorted( faceName );
  }
  wxPGProperty* p = new wxEnumProperty( _T( "Face Name" ), _T( "Face Name" ),
                                        *wxPGGlobalVars->m_fontFamilyChoices );
  p->SetValueFromString( faceName, wxPG_FULL_VALUE );
  AddPrivateChild( p );
  AddPrivateChild( new wxEnumProperty( _T( "Style" ), _T( "Style" ), gs_fp_es_style_labels, gs_fp_es_style_values, font.GetStyle() ) );
  AddPrivateChild( new wxEnumProperty( _T( "Weight" ), _T( "Weight" ), gs_fp_es_weight_labels, gs_fp_es_weight_values, font.GetWeight() ) );
  AddPrivateChild( new wxBoolProperty( _T( "Underlined" ), _T( "Underlined" ), font.GetUnderlined() ) );
}

wxFontProperty::~wxFontProperty() { }

void wxFontProperty::OnSetValue() {
  wxFont& font = wxFontFromVariant( m_value );
  wxASSERT( &font );
  wxFont font2;
  if( !font.Ok() ) {
    font2 = *wxNORMAL_FONT;
  } else {
    font2 = font;
  }
  m_value = wxFontToVariant( font2 );
}

wxString wxFontProperty::GetValueAsString( int argFlags ) const {
  return wxPGProperty::GetValueAsString( argFlags );
}

bool wxFontProperty::OnEvent( wxPropertyGrid* propgrid, wxWindow * ( primary ), wxEvent& event ) {
  if( propgrid->IsMainButtonEvent( event ) ) {
    PrepareValueForDialogEditing( propgrid );
    wxFontData data;
    wxFont font;
    if( m_value.GetType() == _T( "wxFont" ) ) {
      font = wxFontFromVariant( m_value );
    }
    data.SetInitialFont( font );
    data.SetColour( *wxBLACK );
    wxFontDialog dlg( propgrid, data );
    if( dlg.ShowModal() == wxID_OK ) {
      propgrid->EditorsValueWasModified();
      wxVariant variant = wxFontToVariant( dlg.GetFontData().GetChosenFont() );
      SetValueInEvent( variant );
      return true;
    }
  }
  return false;
}

void wxFontProperty::RefreshChildren() {
  if( !GetCount() ) {
    return;
  }
  const wxFont& font = wxFontFromVariant( m_value );
  Item( 0 )->SetValue( ( long )font.GetPointSize() );
  Item( 1 )->SetValue( ( long )font.GetFamily() );
  Item( 2 )->SetValueFromString( font.GetFaceName(), wxPG_FULL_VALUE );
  Item( 3 )->SetValue( ( long )font.GetStyle() );
  Item( 4 )->SetValue( ( long )font.GetWeight() );
  Item( 5 )->SetValue( font.GetUnderlined() );
}

void wxFontProperty::ChildChanged( wxVariant& thisValue, int ind, wxVariant& childValue ) const {
  wxFont& font = wxFontFromVariant( thisValue );
  if( ind == 0 ) {
    font.SetPointSize( wxPGVariantToInt( childValue ) );
  } else if( ind == 1 ) {
    int fam = childValue.GetLong();
    if( fam < wxDEFAULT ||
        fam > wxTELETYPE ) {
      fam = wxDEFAULT;
    }
    font.SetFamily( fam );
  } else if( ind == 2 ) {
    wxString faceName;
    int faceIndex = childValue.GetLong();
    if( faceIndex >= 0 ) {
      faceName = wxPGGlobalVars->m_fontFamilyChoices->GetLabel( faceIndex );
    }
    font.SetFaceName( faceName );
  } else if( ind == 3 ) {
    int st = childValue.GetLong();
    if( st != wxFONTSTYLE_NORMAL &&
        st != wxFONTSTYLE_SLANT &&
        st != wxFONTSTYLE_ITALIC ) {
      st = wxFONTWEIGHT_NORMAL;
    }
    font.SetStyle( st );
  } else if( ind == 4 ) {
    int wt = childValue.GetLong();
    if( wt != wxFONTWEIGHT_NORMAL &&
        wt != wxFONTWEIGHT_LIGHT &&
        wt != wxFONTWEIGHT_BOLD ) {
      wt = wxFONTWEIGHT_NORMAL;
    }
    font.SetWeight( wt );
  } else if( ind == 5 ) {
    font.SetUnderlined( childValue.GetBool() );
  }
}

#define wxPG_PROP_HIDE_CUSTOM_COLOUR   wxPG_PROP_CLASS_SPECIFIC_2

#include <wx/colordlg.h>

static const wxChar* gs_cp_es_syscolour_labels[] = {
  _T( "AppWorkspace" ),
  _T( "ActiveBorder" ),
  _T( "ActiveCaption" ),
  _T( "ButtonFace" ),
  _T( "ButtonHighlight" ),
  _T( "ButtonShadow" ),
  _T( "ButtonText" ),
  _T( "CaptionText" ),
  _T( "ControlDark" ),
  _T( "ControlLight" ),
  _T( "Desktop" ),
  _T( "GrayText" ),
  _T( "Highlight" ),
  _T( "HighlightText" ),
  _T( "InactiveBorder" ),
  _T( "InactiveCaption" ),
  _T( "InactiveCaptionText" ),
  _T( "Menu" ),
  _T( "Scrollbar" ),
  _T( "Tooltip" ),
  _T( "TooltipText" ),
  _T( "Window" ),
  _T( "WindowFrame" ),
  _T( "WindowText" ),
  _T( "Custom" ),
  ( const wxChar* ) NULL
};

static long gs_cp_es_syscolour_values[] = {
  wxSYS_COLOUR_APPWORKSPACE,
  wxSYS_COLOUR_ACTIVEBORDER,
  wxSYS_COLOUR_ACTIVECAPTION,
  wxSYS_COLOUR_BTNFACE,
  wxSYS_COLOUR_BTNHIGHLIGHT,
  wxSYS_COLOUR_BTNSHADOW,
  wxSYS_COLOUR_BTNTEXT,
  wxSYS_COLOUR_CAPTIONTEXT,
  wxSYS_COLOUR_3DDKSHADOW,
  wxSYS_COLOUR_3DLIGHT,
  wxSYS_COLOUR_BACKGROUND,
  wxSYS_COLOUR_GRAYTEXT,
  wxSYS_COLOUR_HIGHLIGHT,
  wxSYS_COLOUR_HIGHLIGHTTEXT,
  wxSYS_COLOUR_INACTIVEBORDER,
  wxSYS_COLOUR_INACTIVECAPTION,
  wxSYS_COLOUR_INACTIVECAPTIONTEXT,
  wxSYS_COLOUR_MENU,
  wxSYS_COLOUR_SCROLLBAR,
  wxSYS_COLOUR_INFOBK,
  wxSYS_COLOUR_INFOTEXT,
  wxSYS_COLOUR_WINDOW,
  wxSYS_COLOUR_WINDOWFRAME,
  wxSYS_COLOUR_WINDOWTEXT,
  wxPG_COLOUR_CUSTOM
};

WX_PG_IMPLEMENT_WXOBJECT_VARIANT_DATA_WITH_PROPER_EQ( wxPGVariantDataColourPropertyValue, wxColourPropertyValue )
WX_PG_IMPLEMENT_PROPERTY_CLASS( wxSystemColourProperty, wxEnumProperty, wxColourPropertyValue, const wxColourPropertyValue&, Choice )

void wxSystemColourProperty::Init( int type, const wxColour& colour ) {
  wxColourPropertyValue cpv;
  if( colour.Ok() ) {
    cpv.Init( type, colour );
  } else {
    cpv.Init( type, *wxWHITE );
  }
  m_flags |= wxPG_PROP_STATIC_CHOICES;
  m_value = wxColourPropertyValueToVariant( cpv );
  OnSetValue();
}

static wxPGChoices gs_wxSystemColourProperty_choicesCache;

wxSystemColourProperty::wxSystemColourProperty( const wxString& label, const wxString& name,
    const wxColourPropertyValue& value )
  : wxEnumProperty( label, name, gs_cp_es_syscolour_labels, gs_cp_es_syscolour_values, &gs_wxSystemColourProperty_choicesCache ) {
  Init( value.m_type, value.m_colour );
}

wxSystemColourProperty::wxSystemColourProperty( const wxString& label, const wxString& name, const wxChar** labels,
    const long* values, wxPGChoices* choicesCache,
    const wxColourPropertyValue& value ) : wxEnumProperty( label, name, labels, values, choicesCache ) {
  Init( value.m_type, value.m_colour );
}

wxSystemColourProperty::wxSystemColourProperty( const wxString& label, const wxString& name, const wxChar** labels,
    const long* values, wxPGChoices* choicesCache,
    const wxColour& value ) : wxEnumProperty( label, name, labels, values, choicesCache ) {
  Init( wxPG_COLOUR_CUSTOM, value );
}

wxSystemColourProperty::~wxSystemColourProperty() { }

wxColourPropertyValue wxSystemColourProperty::GetVal( const wxVariant* pVariant ) const {
  if( !pVariant ) {
    pVariant = &m_value;
  }
  if( pVariant->IsNull() ) {
    return wxColourPropertyValue( wxPG_COLOUR_UNSPECIFIED, wxColour() );
  }
  wxColourPropertyValue* v1 = &wxColourPropertyValueFromVariant( *pVariant );
  if( v1 ) {
    return *v1;
  }
  wxColour* pCol = wxGetVariantCast( *pVariant, wxColour );
  wxColour col;
  if( pCol ) {
    col = *pCol;
  } else {
    col << *pVariant;
  }
  wxColourPropertyValue v2( wxPG_COLOUR_CUSTOM, col );
  int colInd = ColToInd( col );
  if( colInd != wxNOT_FOUND ) {
    v2.m_type = colInd;
  }
  return v2;
}

wxVariant wxSystemColourProperty::DoTranslateVal( wxColourPropertyValue& v ) const {
  return wxColourPropertyValueToVariant( v );
}

int wxSystemColourProperty::ColToInd( const wxColour& colour ) const {
  size_t i;
  size_t i_max = m_choices.GetCount();
  if( !( m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR ) ) {
    i_max -= 1;
  }
  for( i = 0; i < i_max; i++ ) {
    int ind = m_choices[i].GetValue();
    if( colour == GetColour( ind ) ) {
      return ind;
    }
  }
  return wxNOT_FOUND;
}

static inline wxColour wxColourFromPGLong( long col ) {
  return wxColour( ( col & 0xFF ), ( ( col >> 8 ) & 0xFF ), ( ( col >> 16 ) & 0xFF ) );
}

void wxSystemColourProperty::OnSetValue() {
  if( wxPGIsVariantType( m_value, wxobject ) ) {
    wxASSERT( m_value.IsValueKindOf( CLASSINFO( wxColour ) ) );
    wxColour* pCol = ( wxColour* ) m_value.GetWxObjectPtr();
    m_value << *pCol;
  }
  wxColourPropertyValue val = GetVal( &m_value );
  if( val.m_type == wxPG_COLOUR_UNSPECIFIED ) {
    m_value.MakeNull();
    return;
  } else {
    if( val.m_type < wxPG_COLOUR_WEB_BASE ) {
      val.m_colour = GetColour( val.m_type );
    }
    m_value = TranslateVal( val );
  }
  wxColourPropertyValue* pCpv = &wxColourPropertyValueFromVariant( m_value );
  wxColour col;
  if( pCpv ) {
    col = pCpv->m_colour;
  } else {
    col << m_value;
  }
  if( !col.Ok() ) {
    SetValueToUnspecified();
    SetIndex( wxNOT_FOUND );
    return;
  }
  int ind;
  if( pCpv ) {
    if( pCpv->m_type < wxPG_COLOUR_WEB_BASE || ( m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR ) ) {
      ind = GetIndexForValue( pCpv->m_type );
    } else {
      pCpv->m_type = wxPG_COLOUR_CUSTOM;
      ind = GetCustomColourIndex();
    }
  } else {
    ind = ColToInd( col );
    if( ind == wxNOT_FOUND && !( m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR ) ) {
      ind = GetCustomColourIndex();
    }
  }
  SetIndex( ind );
}

wxColour wxSystemColourProperty::GetColour( int index ) const {
  return wxSystemSettings::GetColour( ( wxSystemColour )index );
}

wxString wxSystemColourProperty::ColourToString( const wxColour& col, int index ) const {
  if( index == wxNOT_FOUND ) {
    return wxString::Format( _T( "(%i,%i,%i)" ), ( int )col.Red(), ( int )col.Green(), ( int )col.Blue() );
  } else {
    return m_choices.GetLabel( index );
  }
}

wxString wxSystemColourProperty::GetValueAsString( int argFlags ) const {
  wxColourPropertyValue val = GetVal();
  int ind = GetIndex();
  if( ( val.m_type == wxPG_COLOUR_CUSTOM || ( ind == GetCustomColourIndex() && !( m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR ) ) ||
        ( argFlags & wxPG_PROPERTY_SPECIFIC ) ) ) {
    return ColourToString( val.m_colour, wxNOT_FOUND );
  }
  if( ind == -1 ) {
    return wxEmptyString;
  }
  return ColourToString( val.m_colour, ind );
}

wxSize wxSystemColourProperty::OnMeasureImage( int ) const {
  return wxPG_DEFAULT_IMAGE_SIZE;
}

int wxSystemColourProperty::GetCustomColourIndex() const {
  return m_choices.GetCount() - 1;
}

bool wxSystemColourProperty::QueryColourFromUser( wxVariant& variant ) const {
  wxASSERT( m_value.GetType() != _T( "string" ) );
  bool res = false;
  wxPropertyGrid* propgrid = GetGrid();
  wxASSERT( propgrid );
  if( !( propgrid->GetInternalFlags() & wxPG_FL_IN_ONCUSTOMEDITOREVENT ) ) {
    return res;
  }
  wxColourPropertyValue val = GetVal();
  val.m_type = wxPG_COLOUR_CUSTOM;
  wxColourData data;
  data.SetChooseFull( true );
  data.SetColour( val.m_colour );
  int i;
  for( i = 0; i < 16; i++ ) {
    wxColour colour( i * 16, i * 16, i * 16 );
    data.SetCustomColour( i, colour );
  }
  wxColourDialog dialog( propgrid, &data );
  if( dialog.ShowModal() == wxID_OK ) {
    wxColourData retData = dialog.GetColourData();
    val.m_colour = retData.GetColour();
    variant = DoTranslateVal( val );
    SetValueInEvent( variant );
    res = true;
  }
  return res;
}

bool wxSystemColourProperty::IntToValue( wxVariant& variant, int number, int ( argFlags ) ) const {
  int index = number;
  int type = GetValueForIndex( index );
  if( type == wxPG_COLOUR_CUSTOM ) {
    QueryColourFromUser( variant );
  } else {
    variant = TranslateVal( type, GetColour( type ) );
  }
  return true;
}

bool wxSystemColourProperty::OnEvent( wxPropertyGrid* propgrid, wxWindow * ( primary ), wxEvent& event ) {
  bool askColour = false;
  if( propgrid->IsMainButtonEvent( event ) ) {
    askColour = true;
  } else if( event.GetEventType() == wxEVT_COMMAND_COMBOBOX_SELECTED ) {
    wxPGOwnerDrawnComboBox* cb =
      ( wxPGOwnerDrawnComboBox* )propgrid->GetEditorControl();
    if( cb ) {
      int index = cb->GetSelection();
      if( index == GetCustomColourIndex() &&
          !( m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR ) ) {
        askColour = true;
      }
    }
  }
  if( askColour && !propgrid->WasValueChangedInEvent() ) {
    wxVariant variant;
    if( QueryColourFromUser( variant ) ) {
      return true;
    }
  }
  return false;
}

void wxSystemColourProperty::OnCustomPaint( wxDC& dc, const wxRect& rect, wxPGPaintData& paintdata ) {
  wxColour col;
  if( paintdata.m_choiceItem >= 0 &&
      paintdata.m_choiceItem < ( int )m_choices.GetCount() &&
      ( paintdata.m_choiceItem != GetCustomColourIndex() ||
        m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR ) ) {
    int colInd = m_choices[paintdata.m_choiceItem].GetValue();
    col = GetColour( colInd );
  } else if( !IsValueUnspecified() ) {
    col = GetVal().m_colour;
  }
  if( col.Ok() ) {
    dc.SetBrush( col );
    dc.DrawRectangle( rect );
  }
}


bool wxSystemColourProperty::StringToValue( wxVariant& value, const wxString& text, int argFlags ) const {
  wxString colourName;
  wxString colourRGB;
  int ppos = text.Find( _T( "(" ) );
  if( ppos == wxNOT_FOUND ) {
    colourName = text;
  } else {
    colourName = text.substr( 0, ppos );
    colourRGB = text.substr( ppos, text.length() - ppos );
  }
  colourName.Trim( true );
  colourName.Trim( false );
  colourRGB.Trim( true );
  if( colourRGB.length() < 7 ) {
    colourRGB.clear();
  }
  if( colourRGB.length() == 0 && m_choices.GetCount() &&
      !( m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR ) &&
      colourName == m_choices.GetLabel( GetCustomColourIndex() ) ) {
    if( !( argFlags & wxPG_EDITABLE_VALUE ) ) {
      ResetNextIndex();
      return false;
    }
    QueryColourFromUser( value );
  } else {
    wxColourPropertyValue val;
    bool done = false;
    if( colourName.length() ) {
      bool res = wxEnumProperty::StringToValue( value, colourName, argFlags );
      if( res && GetIndex() >= 0 ) {
        val.m_type = GetIndex();
        if( val.m_type >= 0 && val.m_type < m_choices.GetCount() ) {
          val.m_type = m_choices[val.m_type].GetValue();
        }
        val.m_colour = GetColour( val.m_type );
        done = true;
      }
    }
    if( colourRGB.length() && !done ) {
      val.m_type = wxPG_COLOUR_CUSTOM;
      int r = -1, g = -1, b = -1;
      wxSscanf( colourRGB.c_str(), _T( "(%i,%i,%i)" ), &r, &g, &b );
      if( r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255 ) {
        val.m_colour.Set( r, g, b );
        done = true;
      }
    }
    if( !done ) {
      ResetNextIndex();
      return false;
    }
    value = DoTranslateVal( val );
  }
  return true;
}

bool wxSystemColourProperty::DoSetAttribute( const wxString& name, wxVariant& value ) {
  if( name == wxPG_COLOUR_ALLOW_CUSTOM ) {
    int ival = wxPGVariantToInt( value );
    SetChoicesExclusive();
    if( ival && ( m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR ) ) {
      m_choices.Insert( _T( "Custom" ), GetCustomColourIndex(), wxPG_COLOUR_CUSTOM );
      m_flags &= ~( wxPG_PROP_HIDE_CUSTOM_COLOUR );
    } else if( !ival && !( m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR ) ) {
      m_choices.RemoveAt( GetCustomColourIndex() );
      m_flags |= wxPG_PROP_HIDE_CUSTOM_COLOUR;
    }
    return true;
  }
  return false;
}

static const wxChar* gs_cp_es_normcolour_labels[] = {
  _T( "Black" ),
  _T( "Maroon" ),
  _T( "Navy" ),
  _T( "Purple" ),
  _T( "Teal" ),
  _T( "Gray" ),
  _T( "Green" ),
  _T( "Olive" ),
  _T( "Brown" ),
  _T( "Blue" ),
  _T( "Fuchsia" ),
  _T( "Red" ),
  _T( "Orange" ),
  _T( "Silver" ),
  _T( "Lime" ),
  _T( "Aqua" ),
  _T( "Yellow" ),
  _T( "White" ),
  _T( "Custom" ),
  ( const wxChar* ) NULL
};

static unsigned long gs_cp_es_normcolour_colours[] = {
  wxPG_COLOUR( 0, 0, 0 ),
  wxPG_COLOUR( 128, 0, 0 ),
  wxPG_COLOUR( 0, 0, 128 ),
  wxPG_COLOUR( 128, 0, 128 ),
  wxPG_COLOUR( 0, 128, 128 ),
  wxPG_COLOUR( 128, 128, 128 ),
  wxPG_COLOUR( 0, 128, 0 ),
  wxPG_COLOUR( 128, 128, 0 ),
  wxPG_COLOUR( 166, 124, 81 ),
  wxPG_COLOUR( 0, 0, 255 ),
  wxPG_COLOUR( 255, 0, 255 ),
  wxPG_COLOUR( 255, 0, 0 ),
  wxPG_COLOUR( 247, 148, 28 ),
  wxPG_COLOUR( 192, 192, 192 ),
  wxPG_COLOUR( 0, 255, 0 ),
  wxPG_COLOUR( 0, 255, 255 ),
  wxPG_COLOUR( 255, 255, 0 ),
  wxPG_COLOUR( 255, 255, 255 ),
  wxPG_COLOUR( 0, 0, 0 )
};

WX_PG_IMPLEMENT_CUSTOM_COLOUR_PROPERTY_USES_WXCOLOUR2( wxColourProperty,
    gs_cp_es_normcolour_labels,
    ( const long* )NULL,
    gs_cp_es_normcolour_colours,
    TextCtrlAndButton )

#define wxPG_CURSOR_IMAGE_WIDTH   32
#define NUM_CURSORS   28

static const wxChar* gs_cp_es_syscursors_labels[NUM_CURSORS + 1] = {
  _T( "Default" ),
  _T( "Arrow" ),
  _T( "Right Arrow" ),
  _T( "Blank" ),
  _T( "Bullseye" ),
  _T( "Character" ),
  _T( "Cross" ),
  _T( "Hand" ),
  _T( "I-Beam" ),
  _T( "Left Button" ),
  _T( "Magnifier" ),
  _T( "Middle Button" ),
  _T( "No Entry" ),
  _T( "Paint Brush" ),
  _T( "Pencil" ),
  _T( "Point Left" ),
  _T( "Point Right" ),
  _T( "Question Arrow" ),
  _T( "Right Button" ),
  _T( "Sizing NE-SW" ),
  _T( "Sizing N-S" ),
  _T( "Sizing NW-SE" ),
  _T( "Sizing W-E" ),
  _T( "Sizing" ),
  _T( "Spraycan" ),
  _T( "Wait" ),
  _T( "Watch" ),
  _T( "Wait Arrow" ),
  ( const wxChar* ) NULL
};

static long gs_cp_es_syscursors_values[NUM_CURSORS] = {
  wxCURSOR_NONE,
  wxCURSOR_ARROW,
  wxCURSOR_RIGHT_ARROW,
  wxCURSOR_BLANK,
  wxCURSOR_BULLSEYE,
  wxCURSOR_CHAR,
  wxCURSOR_CROSS,
  wxCURSOR_HAND,
  wxCURSOR_IBEAM,
  wxCURSOR_LEFT_BUTTON,
  wxCURSOR_MAGNIFIER,
  wxCURSOR_MIDDLE_BUTTON,
  wxCURSOR_NO_ENTRY,
  wxCURSOR_PAINT_BRUSH,
  wxCURSOR_PENCIL,
  wxCURSOR_POINT_LEFT,
  wxCURSOR_POINT_RIGHT,
  wxCURSOR_QUESTION_ARROW,
  wxCURSOR_RIGHT_BUTTON,
  wxCURSOR_SIZENESW,
  wxCURSOR_SIZENS,
  wxCURSOR_SIZENWSE,
  wxCURSOR_SIZEWE,
  wxCURSOR_SIZING,
  wxCURSOR_SPRAYCAN,
  wxCURSOR_WAIT,
  wxCURSOR_WATCH,
  wxCURSOR_ARROWWAIT
};

IMPLEMENT_DYNAMIC_CLASS( wxCursorProperty, wxEnumProperty )

wxCursorProperty::wxCursorProperty( const wxString& label, const wxString& name,
                                    int value )
  : wxEnumProperty( label, name, gs_cp_es_syscursors_labels, gs_cp_es_syscursors_values, value ) {
  m_flags |= wxPG_PROP_STATIC_CHOICES;
}

wxCursorProperty::~wxCursorProperty() {
}

wxSize wxCursorProperty::OnMeasureImage( int item ) const {
  return wxSize( 0, 0 );
}

void wxCursorProperty::OnCustomPaint( wxDC&, const wxRect&, wxPGPaintData& ) { }

const wxString& wxPGGetDefaultImageWildcard() {
  if( !wxPGGlobalVars->m_pDefaultImageWildcard.length() ) {
    wxString str;
    wxList& handlers = wxImage::GetHandlers();
    wxList::iterator node;
    for( node = handlers.begin(); node != handlers.end(); node++ ) {
      wxImageHandler *handler = ( wxImageHandler* )*node;
      wxString ext_lo = handler->GetExtension();
      wxString ext_up = ext_lo.Upper();
      str.append( ext_up );
      str.append( _T( " files (*." ) );
      str.append( ext_up );
      str.append( _T( ")|*." ) );
      str.append( ext_lo );
      str.append( _T( "|" ) );
    }
    str.append( _T( "All files (*.*)|*.*" ) );
    wxPGGlobalVars->m_pDefaultImageWildcard = str;
  }
  return wxPGGlobalVars->m_pDefaultImageWildcard;
}

WX_PG_IMPLEMENT_DERIVED_PROPERTY_CLASS( wxImageFileProperty, wxFileProperty, const wxString& )

wxImageFileProperty::wxImageFileProperty( const wxString& label, const wxString& name,
    const wxString& value )
  : wxFileProperty( label, name, value ) {
  SetAttribute( wxPG_FILE_WILDCARD, wxPGGetDefaultImageWildcard() );
  m_pImage = ( wxImage* ) NULL;
  m_pBitmap = ( wxBitmap* ) NULL;
}

wxImageFileProperty::~wxImageFileProperty() {
  if( m_pBitmap ) {
    delete m_pBitmap;
  }
  if( m_pImage ) {
    delete m_pImage;
  }
}

void wxImageFileProperty::OnSetValue() {
  wxFileProperty::OnSetValue();
  if( m_pImage ) {
    delete m_pImage;
    m_pImage = NULL;
  }
  if( m_pBitmap ) {
    delete m_pBitmap;
    m_pBitmap = NULL;
  }
  if( m_filename.FileExists() ) {
    m_pImage = new wxImage( m_filename.GetFullPath() );
  }
}

wxSize wxImageFileProperty::OnMeasureImage( int ) const {
  return wxPG_DEFAULT_IMAGE_SIZE;
}

void wxImageFileProperty::OnCustomPaint( wxDC& dc, const wxRect& rect, wxPGPaintData& ) {
  if( m_pBitmap || ( m_pImage && m_pImage->Ok() ) ) {
    if( !m_pBitmap ) {
      m_pImage->Rescale( rect.width, rect.height );
      m_pBitmap = new wxBitmap( *m_pImage );
      delete m_pImage;
      m_pImage = NULL;
    }
    dc.DrawBitmap( *m_pBitmap, rect.x, rect.y, false );
  } else {
    dc.SetBrush( *wxWHITE_BRUSH );
    dc.DrawRectangle( rect );
  }
}

#include <wx/choicdlg.h>

WX_PG_IMPLEMENT_PROPERTY_CLASS( wxMultiChoiceProperty, wxPGProperty,
                                wxArrayInt, const wxArrayInt&, TextCtrlAndButton )

wxMultiChoiceProperty::wxMultiChoiceProperty( const wxString& label,
    const wxString& name, const wxPGChoices& choices, const wxArrayString& value )
  : wxPGProperty( label, name ) {
  m_choices.Assign( choices );
  SetValue( value );
}

wxMultiChoiceProperty::wxMultiChoiceProperty( const wxString& label,
    const wxString& name, const wxArrayString& strings, const wxArrayString& value )
  : wxPGProperty( label, name ) {
  m_choices.Set( strings );
  SetValue( value );
}

wxMultiChoiceProperty::wxMultiChoiceProperty( const wxString& label, const wxString& name,
    const wxArrayString& value )
  : wxPGProperty( label, name ) {
  wxArrayString strings;
  m_choices.Set( strings );
  SetValue( value );
}

wxMultiChoiceProperty::~wxMultiChoiceProperty() {
}

void wxMultiChoiceProperty::OnSetValue() {
  GenerateValueAsString();
}

wxString wxMultiChoiceProperty::GetValueAsString( int ) const {
  return m_display;
}

void wxMultiChoiceProperty::GenerateValueAsString() {
  wxArrayString strings;
  if( wxPGIsVariantType( m_value, arrstring ) ) {
    strings = m_value.GetArrayString();
  }
  wxString& tempStr = m_display;
  unsigned int i;
  unsigned int itemCount = strings.GetCount();
  tempStr.Empty();
  if( itemCount ) {
    tempStr.append( _T( "\"" ) );
  }
  for( i = 0; i < itemCount; i++ ) {
    tempStr.append( strings[i] );
    tempStr.append( _T( "\"" ) );
    if( i < ( itemCount - 1 ) ) {
      tempStr.append( _T( " \"" ) );
    }
  }
}

wxArrayInt wxMultiChoiceProperty::GetValueAsIndices() const {
  const wxArrayInt& valueArr = wxArrayIntFromVariant( GetValue() );
  unsigned int i;
  wxArrayInt selections;
  if( !m_choices.IsOk() || !m_choices.GetCount() ) {
    for( i = 0; i < valueArr.GetCount(); i++ ) {
      selections.Add( -1 );
    }
  } else {
    for( i = 0; i < valueArr.GetCount(); i++ ) {
      int sIndex = m_choices.Index( valueArr[i] );
      if( sIndex >= 0 ) {
        selections.Add( sIndex );
      }
    }
  }
  return selections;
}

bool wxMultiChoiceProperty::OnEvent( wxPropertyGrid* propgrid, wxWindow * ( primary ), wxEvent& event ) {
  if( propgrid->IsMainButtonEvent( event ) ) {
    PrepareValueForDialogEditing( propgrid );
    wxArrayString labels = m_choices.GetLabels();
    unsigned int choiceCount;
    if( m_choices.IsOk() ) {
      choiceCount = m_choices.GetCount();
    } else
    { choiceCount = 0; }
    wxMultiChoiceDialog dlg( propgrid, _T( "进行选择:" ), m_label, choiceCount, choiceCount ? &labels[0] : NULL, wxCHOICEDLG_STYLE );
    dlg.Move( propgrid->GetGoodEditorDialogPosition( this, dlg.GetSize() ) );
    wxArrayString strings = m_value.GetArrayString();
    wxArrayString extraStrings;
    dlg.SetSelections( m_choices.GetIndicesForStrings( strings, &extraStrings ) );
    if( dlg.ShowModal() == wxID_OK && choiceCount ) {
      int userStringMode = GetAttributeAsLong( _T( "UserStringMode" ), 0 );
      wxArrayInt arrInt = dlg.GetSelections();
      wxVariant variant;
      wxArrayString value;
      unsigned int n;
      if( userStringMode == 1 ) {
        for( n = 0; n < extraStrings.size(); n++ ) {
          value.push_back( extraStrings[n] );
        }
      }
      unsigned int i;
      for( i = 0; i < arrInt.GetCount(); i++ ) {
        value.Add( m_choices.GetLabel( arrInt.Item( i ) ) );
      }
      if( userStringMode == 2 ) {
        for( n = 0; n < extraStrings.size(); n++ ) {
          value.push_back( extraStrings[n] );
        }
      }
      variant = WXVARIANT( value );
      SetValueInEvent( variant );
      return true;
    }
  }
  return false;
}

int wxMultiChoiceProperty::GetChoiceInfo( wxPGChoiceInfo* choiceinfo ) {
  if( choiceinfo ) {
    choiceinfo->m_choices = &m_choices;
  }
  return -1;
}

bool wxMultiChoiceProperty::StringToValue( wxVariant& variant, const wxString& text, int ) const {
  wxArrayString arr;
  int userStringMode = GetAttributeAsLong( _T( "UserStringMode" ), 0 );
  WX_PG_TOKENIZER2_BEGIN( text, _T( '"' ) )
  if( userStringMode > 0 || ( m_choices.IsOk() && m_choices.Index( token ) != wxNOT_FOUND ) ) {
    arr.Add( token );
  }
  WX_PG_TOKENIZER2_END()
  wxVariant v( arr );
  variant = v;
  return true;
}

#define dtCtrl  DatePickerCtrl

WX_PG_IMPLEMENT_PROPERTY_CLASS( wxDateProperty, wxPGProperty, wxDateTime, const wxDateTime&, dtCtrl )
wxString wxDateProperty::ms_defaultDateFormat;

wxDateProperty::wxDateProperty( const wxString& label, const wxString& name, const wxDateTime& value )
  : wxPGProperty( label, name ) {
  wxPGRegisterEditorClass( DatePickerCtrl );
  m_dpStyle = wxDP_DEFAULT | wxDP_SHOWCENTURY;
  SetValue( value );
}

wxDateProperty::~wxDateProperty() {
}

void wxDateProperty::OnSetValue() {
  if( m_value.GetType() == _T( "datetime" ) ) {
    if( !m_value.GetDateTime().IsValid() ) {
      m_value.MakeNull();
    }
  }
}

bool wxDateProperty::StringToValue( wxVariant& variant, const wxString& text, int ( argFlags ) ) const {
  wxDateTime dt;
  const wxChar* c = dt.ParseFormat( text, wxDefaultDateTimeFormat );
  if( c ) {
    variant = dt;
    return true;
  }
  return false;
}

wxString wxDateProperty::GetValueAsString( int argFlags ) const {
  const wxChar* format = ( const wxChar* ) NULL;
  wxDateTime dateTime = m_value.GetDateTime();
  if( !dateTime.IsValid() ) {
    return _T( "Invalid" );
  }
  if( !ms_defaultDateFormat.length() ) {
    bool showCentury = m_dpStyle & wxDP_SHOWCENTURY ? true : false;
    ms_defaultDateFormat = DetermineDefaultDateFormat( showCentury );
  }
  if( m_format.length() &&
      !( argFlags & wxPG_FULL_VALUE ) ) {
    format = m_format.c_str();
  }
  if( !format ) {
    format = ms_defaultDateFormat.c_str();
  }
  return dateTime.Format( format );
}

wxString wxDateProperty::DetermineDefaultDateFormat( bool showCentury ) {
  wxString format;
  wxDateTime dt;
  dt.ParseFormat( _T( "2003-10-13" ), _T( "%Y-%m-%d" ) );
  wxString str( dt.Format( _T( "%x" ) ) );
  const wxChar *p = str.c_str();
  while( *p ) {
    int n = wxAtoi( p );
    if( n == dt.GetDay() ) {
      format.Append( _T( "%d" ) );
      p += 2;
    } else if( n == ( int )dt.GetMonth() + 1 ) {
      format.Append( _T( "%m" ) );
      p += 2;
    } else if( n == dt.GetYear() ) {
      format.Append( _T( "%Y" ) );
      p += 4;
    } else if( n == ( dt.GetYear() % 100 ) ) {
      if( showCentury ) {
        format.Append( _T( "%Y" ) );
      } else
      { format.Append( _T( "%y" ) ); }
      p += 2;
    } else
    { format.Append( *p++ ); }
  }
  return format;
}

bool wxDateProperty::DoSetAttribute( const wxString& name, wxVariant& value ) {
  if( name == wxPG_DATE_FORMAT ) {
    m_format = value.GetString();
    return true;
  } else if( name == wxPG_DATE_PICKER_STYLE ) {
    m_dpStyle = value.GetLong();
    ms_defaultDateFormat.clear();
    return true;
  }
  return false;
}

void wxPropertyGridInterface::InitAllTypeHandlers() {
}

void wxPropertyGridInterface::RegisterAdditionalEditors() {
  wxPGRegisterEditorClass( SpinCtrl );
  wxPGRegisterEditorClass( DatePickerCtrl );
}
